/**
 * 
 * @File    : 
 * @Brief   : ... 
 * @Version : 1.0
 * @Author  : 靳普诏
 * @E-Mail  : 499367619@qq.com
 */
/**
 * @addtogroup sfc_thread.h
 * sfc_thread.h
 * @{
 */
/**
 * @file sfc_thread.h
 * @brief 定义Thread类
 * @note
 * @author Leo

 * @par          修改日志
 * <table>
 * <tr><th>Date <th>Version <th>Author <th>Description
 * <tr><td>2019-07-03 <td>1.0 <td>Leo <td>创建初始版本
 * <tr><td>2020-11-19 <td>1.1 <td>Leo <td>增加Kill线程的接口
 * <tr><td>2021-07-19 <td>1.2 <td>Leo <td>解决bug: TSfThreadWaitFor中调用osThreadDetach,用于释放资源
 * @copyright 杭州鸿泉物联网技术股份有限公司
 */
#ifndef _SFC_THREAD_H_
#define _SFC_THREAD_H_

#include <ofc_object.h>
#include "sfc_api.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
 * 构造一个线程类
 * @par 示例
 * @code
    // 定义一个线程用的堆栈,并且该堆栈以8字节对齐
    __align(8) static char stack[512];
    TSfThreadCreate(&self->thread_, kSfThreadPriorityNormal, stack, sizeof(stack));
    self->thread_.receiver = (void *)self;
    self->thread_.OnRunOnce = TMainTaskRunOnce;
    if (TSfThreadResume(&self->thread_))
    {
		...
	   
    }
   
    TSfThreadTerminate(&self->thread_);
    TSfThreadWaitFor(&self->thread_, 3000);
    OfDestroyObject((TOfObject *)&self->thread_);
 * @endcode
 */

typedef struct TSfThreadTag TSfThread;

/** 线程的执行事件 */
typedef Int32 (*TSfThreadExecute)(TSfThread *sender);

struct TSfThreadTag
{
PRIVATE
    TSfThreadHandle handle_; ///< 线程句柄
    void *stack_;      ///< 线程的堆栈
    Int32 stack_size_;   ///< 堆栈大小
    Bool terminated_;  ///< 线程结束标记
    TSfThreadPriority priority_;  ///< 线程优先级
    char name_[16];    ///< 线程的名称
    int thread_id_;    ///< 线程ID

PUBLIC
    void *receiver;  ///< 存放用户数据.一般存放OnExecute或者OnRunOnce的对象实例

    TSfThreadExecute OnExecute;  ///< 线程实际的执行事件,一般来说,事件中会包含循环体. 如果这个事件被赋值的话,OnRunOnce事件就无效
    TSfThreadExecute OnRunOnce;  ///< 线程的单次执行事件,线程执行过程中会重复调用该事件,两次执行的间隔为上次执行该事件的返回值,单位: ms.
};

/* 线程属性 */
typedef struct TSfThreadAttrTag TSfThreadAttr;
struct TSfThreadAttrTag
{
    const char *name;   ///< 线程的名称
    void *stack;        ///< 线程的堆栈,可以为空,用默认的堆栈; 注意: 线程的堆栈必须是8字节对齐的,既: 堆栈的起始地址必须是8的倍数
    Int32 stack_size;   ///< 线程的堆栈大小,可以为0,用默认的堆栈大小
    TSfThreadPriority priority; ///< 线程优先级
};

/**
 * 线程类的构造函数.
 * @note 构造函数并没有创建线程,需要调用TSfThreadResume创建线程
 * @param self: 对象实例指针
 * @param priority: 线程的优先级.**注意**: 高优先级的线程如果不等待,低优先级的线程将得不到运行的机会
 * @param stack: 线程的堆栈,可以为空,用默认的堆栈; 注意: 线程的堆栈必须是8字节对齐的,既: 堆栈的起始地址必须是8的倍数
 * @param stack_size: 线程的堆栈大小,可以为0,用默认的堆栈大小
 * @return 返回创建是否成功; 创建成功返回True,参数错误(堆栈起始地址不是8字节对齐)则创建失败返回False
 */
Bool TSfThreadCreate(TSfThread *self, TSfThreadPriority priority, void *stack, Int32 stack_size);

/**
 * 线程类的构造函数(使用线程属性)
 * @note 构造函数并没有创建线程,需要调用TSfThreadResume创建线程
 * @param self: 对象实例指针
 * @param attr: 线程属性
 * @return 返回创建是否成功; 创建成功返回True,参数错误(堆栈起始地址不是8字节对齐)则创建失败返回False
 */
Bool TSfThreadCreateEx(TSfThread *self, const TSfThreadAttr *attr);


/**
 * 销毁线程对象
 * @param self: 对象实例指针
 * @note 该函数会终止线程的运行,等待线程退出,然后释放线程相关的资源
 * @note 调用此函数前需确保线程已经停止运行或者可以正常退出,否则可能会导致资源泄露
 * @note 如果线程正在运行中,该函数会阻塞等待线程退出
 */
void TSfThreadDestroy(TSfThread *self);

/**
 * 线程如果在创建时挂起,则恢复运行.如果已经运行则不作操作
 * @param self: 对象实例
 * @return 创建失败返回False,创建成功返回True
 */
Bool TSfThreadResume(TSfThread *self);

/**
 * 终止线程的允许.事实上只是设置线程的terminated_变量为true,是否真正退出要看执行函数有没有退出
 * @param self: 对象实例指针
 * @return 无返回值
 */
void TSfThreadTerminate(TSfThread *self);

/**
 * 返回线程是否需要终止线程
 * @param self: 对象实例指针
 * @return true: 需要终止; false: 不需要终止
 */
Bool TSfThreadTerminated(TSfThread *self);

/**
 * 等待线程退出
 * @param self: 对象实例指针
 * @param timeout: 超时时长,单位: ms; 注意: 该参数在RTOS系统上没有用,填0即可
 * @return True: 成功: False: 失败
 */
Bool TSfThreadWaitFor(TSfThread *self, UInt32 timeout);

/**
 * 返回线程的句柄
 * @param self: 对象实例指针
 * @return 线程句柄.如果线程没有运行起来,返回的句柄为NULL
 */
TSfThreadHandle TSfThreadGetHandle(TSfThread *self);

/**
 * 返回线程是否在运行
 * @param self: 对象实例指针
 * @return 线程正在运行,返回true,否则返回false
 */
Bool TSfThreadRunning(TSfThread *self);

/**
 * 线程ID,RTX操作系统为句柄,linux为线程Id
 * @param self: 对象指针
 * @return 返回线程ID
 */
Long TSfThreadThreadId(TSfThread *self);

/**
 * 强行结束线程
 * @param self: 对象实例指针
 * @return 结束成功返回True,否则返回False
 */
Bool TSfThreadKill(TSfThread *self);

/**
 * 获取当前线程Id
 * @return 返回当前线程的ID
 */
Long SfGetCurrentThreadId(void);

/**
 * 根据执行期间的堆栈水位线记录，获取线程的可用堆栈空间
 * @note 需要底层实时操作系统（RTOS）的支持。当底层RTOS不支持此功能时，返回False或返回0。
 * @note 在底层RTOS中支持此功能的典型方法是检查堆栈内容，并与预设的魔术字节或字进行比较。
 * @param handle: 线程句柄
 * @param space: 可用堆栈空间
 * @return Ture: 成功; False: 失败
 */
Bool SfThreadGetStackSpace(TSfThreadHandle handle, UInt32 *space);

/**
 * 获取线程的名称
 * @note 需要底层实时操作系统（RTOS）的支持。当底层RTOS不支持此功能时或没有名称，返回NULL。
 * @note 如果任务在填充结构后被删除，该值将无效！
 * @param handle: 线程句柄
 * @return 线程的名称
 */
const char *SfThreadGetName(TSfThreadHandle handle);

#ifdef __cplusplus
}  // extern "C"
#endif

#endif  // _SFC_THREAD_H_

/**
 * @}
 */
